
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       task_serial.c
  * @author     baiyang
  * @date       2021-7-15
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include "task_serial.h"

#include <rthw.h>

#include <common/microbee.h>
#include <common/console/console.h>
#include <parameter/param.h>
#include <common/time/gp_time.h>
#include <board_config/borad_config.h>
/*-----------------------------------macro------------------------------------*/
#define SERIAL_SEND_INTERVAL 5
/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/

/*----------------------------------variable----------------------------------*/
struct gp_serial_thread serial[GP_SERIAL_COUNT_MAX];

// 串口通信用线程
static char thread_serial_rx_task_stack[256];
struct rt_thread thread_serial_rx_task_handle;

static char thread_serial0_task_stack[256];
struct rt_thread thread_serial0_task_handle;

static char thread_serial1_task_stack[384];
struct rt_thread thread_serial1_task_handle;

static char thread_serial2_task_stack[384];
struct rt_thread thread_serial2_task_handle;

static char thread_serial3_task_stack[384];
struct rt_thread thread_serial3_task_handle;

static char thread_serial4_task_stack[384];
struct rt_thread thread_serial4_task_handle;

static char thread_serial5_task_stack[384];
struct rt_thread thread_serial5_task_handle;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
  * @brief       UART发送完成回调,DMA发送完成释放信号量
  * @param[in]   dev  
  * @param[in]   buffer  
  * @param[out]  
  * @retval      
  * @note        
  */
static rt_err_t _uart_tx_done(rt_device_t dev, void* buffer)
{
    for(uint8_t i = 0; i < 8; i++)
    {
        if(serial[i].sdevice != RT_NULL)
        {
            if(serial[i].sdevice->puart == dev)
            {
                return rt_sem_release(serial[i].tx_sem);
            }
        }
    }
    
    RT_ASSERT(0);
    return RT_FALSE;
}

/**
  * @brief       循环开始前的初始化
  * @param[in]   thread  
  * @param[out]  
  * @retval      
  * @note        
  */
static void serial_thread_init(gp_serial_thread_t thread)
{
    thread->res = 0;

    RT_ASSERT(thread->sdevice != RT_NULL);
    RT_ASSERT(thread->sdevice->puart != RT_NULL);

    if(thread->sdevice->oflag & RT_DEVICE_FLAG_DMA_TX) //DMA模式下需要信号量触发回调
    {
        thread->tx_sem = rt_sem_create(thread->sem_name, 0, RT_IPC_FLAG_FIFO);

        if (!thread->tx_sem) {
            brd_config_error("function:%s, line number:%d, tx_sem is NULL\n",__FUNCTION__, __LINE__);
        }

        rt_device_set_tx_complete(thread->sdevice->puart, _uart_tx_done);
    }
}

// record timestamp of new incoming data
static void receive_timestamp_update(gp_serial_thread_t thread)
{
    thread->sdevice->receive_timestamp[thread->sdevice->receive_timestamp_idx^1] = time_micros64();
    thread->sdevice->receive_timestamp_idx ^= 1;
}

/**
  * @brief       循环接收
  * @param[in]   thread  
  * @param[out]  
  * @retval      
  * @note        
  */
static bool serial_rx_loop(gp_serial_thread_t thread)
{
    if (thread == NULL || thread->sdevice == NULL || thread->sdevice->puart == NULL) {
        return false;
    }

    rt_size_t size = 0;

    //从UART缓冲区读取数据,并写入SERIAL缓冲区rb_rx
    uint8_t rec_data[64];

    while(true)
    {
        rt_size_t rec_data_size = rt_device_read(thread->sdevice->puart, 0, rec_data, sizeof(rec_data));

        if (rec_data_size == 0) {
            break;
        }

        /* disable interrupt */
        rt_base_t level = rt_hw_interrupt_disable();

        rt_ringbuffer_put_force(thread->sdevice->rb_rx,rec_data,rec_data_size);

        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        size += rec_data_size;
    }

    if (size > 0) {
        receive_timestamp_update(thread);

        if(thread->sdevice->parent.rx_indicate != RT_NULL)
        {
            thread->sdevice->parent.rx_indicate(&thread->sdevice->parent, rt_ringbuffer_data_len(thread->sdevice->rb_rx)); //如果上次数据读完，进入接受完成回调
        }
    }

    return true;
}

/**
  * @brief       循环发送
  * @param[in]   thread  
  * @param[out]  
  * @retval      
  * @note        
  */
static void serial_tx_loop(gp_serial_thread_t thread)
{
    // 从SERIAL缓冲区rb_tx读取数据,使用UART驱动发送
    rt_base_t level = rt_hw_interrupt_disable();

    thread->buf.send_len = rt_ringbuffer_data_len(thread->sdevice->rb_tx);
    if( thread->buf.send_len ) {
        uint16_t len = thread->buf.send_len > GP_SERRIAL_SEND_BUFF_LEN ? GP_SERRIAL_SEND_BUFF_LEN : thread->buf.send_len;

        rt_ringbuffer_get(thread->sdevice->rb_tx, thread->buf.send_data, len);

        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        rt_device_write(thread->sdevice->puart, 0, thread->buf.send_data, len);

        if (thread->sdevice->parent.open_flag & RT_DEVICE_FLAG_INT_TX) {
            if(thread->sdevice->parent.tx_complete != RT_NULL) {
                thread->sdevice->parent.tx_complete(&thread->sdevice->parent, (void *)thread->buf.send_data); //发送完成回调，测试没问题,目前在event_task线程中测试
            }
        }
#ifdef RT_SERIAL_USING_DMA
        else if (thread->sdevice->parent.open_flag & RT_DEVICE_FLAG_DMA_TX) {
            rt_sem_take(thread->tx_sem,  rt_tick_from_millisecond(200)); //等待信号量（表示DMA发送完成）

            if(thread->sdevice->parent.tx_complete != RT_NULL) {
                thread->sdevice->parent.tx_complete(&thread->sdevice->parent, (void *)thread->buf.send_data); //发送完成回调，测试没问题,目前在event_task线程中测试
            }
        }
#endif /* RT_SERIAL_USING_DMA */

    }else {
        /* enable interrupt */
        rt_hw_interrupt_enable(level);
    }
}

/*----------------------------------serial rx--------------------------------*/

static void serial_init()
{
    serial[0].name = "serial0";
    serial[0].sem_name = "s0_sem";
    serial[0].sdevice = (gp_serial_device_t)rt_device_find(serial[0].name);  //查找设备

    serial[1].name = "serial1";
    serial[1].sem_name = "s1_sem";
    serial[1].sdevice = (gp_serial_device_t)rt_device_find(serial[1].name);  //查找设备

    serial[2].name = "serial2";
    serial[2].sem_name = "s2_sem";
    serial[2].sdevice = (gp_serial_device_t)rt_device_find(serial[2].name);  //查找设备

    serial[3].name = "serial3";
    serial[3].sem_name = "s3_sem";
    serial[3].sdevice = (gp_serial_device_t)rt_device_find(serial[3].name);  //查找设备


    serial[4].name = "serial4";
    serial[4].sem_name = "s4_sem";
    serial[4].sdevice = (gp_serial_device_t)rt_device_find(serial[4].name);  //查找设备

    serial[5].name = "serial5";
    serial[5].sem_name = "s5_sem";
    serial[5].sdevice = (gp_serial_device_t)rt_device_find(serial[5].name);  //查找设备
}

/*---------------------------------serial rx---------------------------------*/
/**
  * @brief       
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial_rx_main(void *parameter)
{
    while(1)
    {
        rt_thread_mdelay(1);

        for (uint8_t i=0; i<GP_SERIAL_COUNT_MAX; i++) {
            if (serial[i].sdevice == NULL || serial[i].sdevice->protocol == SerialProtocol_None) {
                continue;
            }

            serial_rx_loop(&serial[i]);
        }
    }
}
/*----------------------------------serial0----------------------------------*/
/**
  * @brief       serial接收线程主函数
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial0_main(void *parameter)
{
    rt_device_t serial_dev = rt_device_find(serial[0].name);
    
    if(serial_dev == RT_NULL)
    {
        return;
    }

    serial[0].buf.send_data = (uint8_t *)rt_malloc(GP_SERRIAL_SEND_BUFF_LEN);

    if (serial[0].buf.send_data == NULL) {
        return;
    }

    serial_thread_init(&serial[0]);

    while(1)
    {
        serial_tx_loop(&serial[0]);
        rt_thread_mdelay(SERIAL_SEND_INTERVAL);
    }
}

/*----------------------------------serial1----------------------------------*/
/**
  * @brief       serial1线程主函数
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial1_main(void *parameter)
{
    rt_device_t serial_dev = rt_device_find(serial[1].name);
    
    if(PARAM_GET_INT8(SERIAL, SERIAL1_PROTOCOL) == SerialProtocol_None \
        || serial_dev == RT_NULL)
    {
        return;
    }

    serial[1].buf.send_data = (uint8_t *)rt_malloc(GP_SERRIAL_SEND_BUFF_LEN);

    if (serial[1].buf.send_data == NULL) {
        return;
    }

    serial_thread_init(&serial[1]);

    while(1)
    {
        serial_tx_loop(&serial[1]);
        rt_thread_mdelay(SERIAL_SEND_INTERVAL);
    }
}


/*----------------------------------serial2----------------------------------*/

/**
  * @brief       serial2线程主函数
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial2_main(void *parameter)
{
    rt_device_t serial_dev = rt_device_find(serial[2].name);

    if(PARAM_GET_INT8(SERIAL, SERIAL2_PROTOCOL) == SerialProtocol_None \
        || serial_dev == RT_NULL)
    {
        return;
    }

    serial[2].buf.send_data = (uint8_t *)rt_malloc(GP_SERRIAL_SEND_BUFF_LEN);

    if (serial[2].buf.send_data == NULL) {
        return;
    }

    serial_thread_init(&serial[2]);

    while(1)
    {
        serial_tx_loop(&serial[2]);
        rt_thread_mdelay(SERIAL_SEND_INTERVAL);
    }
}

/*----------------------------------serial3----------------------------------*/
/**
  * @brief       serial3线程主函数
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial3_main(void *parameter)
{
    rt_device_t serial_dev = rt_device_find(serial[3].name);

    if(PARAM_GET_INT8(SERIAL, SERIAL3_PROTOCOL) == SerialProtocol_None \
        || serial_dev == RT_NULL)
    {
        return;
    }

    serial[3].buf.send_data = (uint8_t *)rt_malloc(GP_SERRIAL_SEND_BUFF_LEN);

    if (serial[3].buf.send_data == NULL) {
        return;
    }

    serial_thread_init(&serial[3]);

    while(1)
    {
        serial_tx_loop(&serial[3]);
        rt_thread_mdelay(SERIAL_SEND_INTERVAL);
    }
}

/*----------------------------------serial4----------------------------------*/
/**
  * @brief       serial4线程主函数
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial4_main(void *parameter)
{
    rt_device_t serial_dev = rt_device_find(serial[4].name);

    if(PARAM_GET_INT8(SERIAL, SERIAL4_PROTOCOL) == SerialProtocol_None \
        || serial_dev == RT_NULL)
    {
        return;
    }

    serial[4].buf.send_data = (uint8_t *)rt_malloc(GP_SERRIAL_SEND_BUFF_LEN);

    if (serial[4].buf.send_data == NULL) {
        return;
    }

    serial_thread_init(&serial[4]);

    while(1)
    {
        serial_tx_loop(&serial[4]);
        rt_thread_mdelay(SERIAL_SEND_INTERVAL);
    }
}

/*----------------------------------serial5----------------------------------*/
/**
  * @brief       serial5线程主函数
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
void serial5_main(void *parameter)
{
    rt_device_t serial_dev = rt_device_find(serial[5].name);

    if(PARAM_GET_INT8(SERIAL, SERIAL5_PROTOCOL) == SerialProtocol_None \
        || serial_dev == RT_NULL)
    {
        return;
    }

    serial[5].buf.send_data = (uint8_t *)rt_malloc(GP_SERRIAL_SEND_BUFF_LEN);

    if (serial[5].buf.send_data == NULL) {
        return;
    }

    serial_thread_init(&serial[5]);

    while(1)
    {
        serial_tx_loop(&serial[5]);
        rt_thread_mdelay(SERIAL_SEND_INTERVAL);
    }
}

rt_err_t task_serial_init(void)
{
    rt_err_t res;

    gp_serial_device_init();

    serial_init();

    res = rt_thread_init(&thread_serial_rx_task_handle,
                           "serialrx",
                           serial_rx_main,
                           RT_NULL,
                           &thread_serial_rx_task_stack[0],
                           sizeof(thread_serial_rx_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial_rx_task_handle);

    res = rt_thread_init(&thread_serial0_task_handle,
                           "serial0",
                           serial0_main,
                           RT_NULL,
                           &thread_serial0_task_stack[0],
                           sizeof(thread_serial0_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial0_task_handle);

    res = rt_thread_init(&thread_serial1_task_handle,
                           "serial1",
                           serial1_main,
                           RT_NULL,
                           &thread_serial1_task_stack[0],
                           sizeof(thread_serial1_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial1_task_handle);

    res = rt_thread_init(&thread_serial2_task_handle,
                           "serial2",
                           serial2_main,
                           RT_NULL,
                           &thread_serial2_task_stack[0],
                           sizeof(thread_serial2_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial2_task_handle);

    res = rt_thread_init(&thread_serial3_task_handle,
                           "serial3",
                           serial3_main,
                           RT_NULL,
                           &thread_serial3_task_stack[0],
                           sizeof(thread_serial3_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial3_task_handle);

    res = rt_thread_init(&thread_serial4_task_handle,
                           "serial4",
                           serial4_main,
                           RT_NULL,
                           &thread_serial4_task_stack[0],
                           sizeof(thread_serial4_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial4_task_handle);

    res = rt_thread_init(&thread_serial5_task_handle,
                           "serial5",
                           serial5_main,
                           RT_NULL,
                           &thread_serial5_task_stack[0],
                           sizeof(thread_serial5_task_stack),PRIORITY_UART,5);
    if (res == RT_EOK)
        rt_thread_startup(&thread_serial5_task_handle);

    return RT_EOK;
}

/*------------------------------------test------------------------------------*/


